package com.es.demo.task;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * 这个类的作用是将所有的业务任务方法都通过这个类包装一下，通过spring获取bean对象和java反射获取执行方法去执行实际业务，也可以想xxl一样定义一个注解，然后去扫描这个注解获取业务方法也行
 * 用重写equals和hashcode方法控制任务的唯一性，同时做通用日志打印，现在用bean、方法名、参数来检验唯一性，可根据业务是否添加cron条件
 */
@Slf4j
public class ScheduleRunnalbe implements Runnable {

    private String cron;
    private String beanName;
    private String methodName;
    private Object[] params;

    public ScheduleRunnalbe(String cron, String beanName, String methodName, Object... params) {
        this.cron = cron;
        this.beanName = beanName;
        this.methodName = methodName;
        this.params = params;
    }

    @Override
    public void run() {
        log.info("定时任务开始执行:beanName{},methodName{},params{}, cron{}", beanName, methodName, params, cron);
        try {
            Object target = SpringContextUtil.getBean(beanName);
            Method method = null;
            if (params != null && params.length > 0) {
                Class<?>[] paramCls = new Class[params.length];
                for (int i = 0; i < params.length; i++) {
                    paramCls[i] = params[i].getClass();
                }
                method = target.getClass().getDeclaredMethod(methodName, paramCls);
            } else {
                method = target.getClass().getDeclaredMethod(methodName);
            }

            ReflectionUtils.makeAccessible(method);
            if(params != null && params.length > 0) {
                method.invoke(target, params);
            } else {
                method.invoke(target);
            }
        } catch (Exception e) {
            log.error("定时任务报错e={}", e);
        }
        log.info("定时任务结束:beanName{},methodName{},params{}, cron{}", beanName, methodName, params, cron);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ScheduleRunnalbe that = (ScheduleRunnalbe) o;
        if (params == null) {
            return beanName.equals(that.beanName) &&
                    methodName.equals(that.methodName) &&
                    that.params == null;
        }

        return beanName.equals(that.beanName) &&
                methodName.equals(that.methodName) &&
                Arrays.equals(params, that.params);
    }

    @Override
    public int hashCode() {
        if (params == null) {
            return Objects.hash(beanName, methodName);
        }

        return Objects.hash(beanName, methodName, Arrays.hashCode(params));
    }
}
